package com.stress.testing.plugin.nosql.redis.interceptor;

import com.stress.testing.common.StressTesting;
import com.stress.testing.common.TraceContextHolder;
import com.stress.testing.common.conf.AgentConfig;
import com.stress.testing.common.conf.PluginConfig;
import com.stress.testing.common.interceptor.AbstractInterceptor;
import com.stress.testing.common.interceptor.InvokeResult;
import com.stress.testing.plugin.nosql.redis.resolver.JedisMethodArgsResolver;
import com.stress.testing.plugin.nosql.redis.resolver.ResolveResult;
import com.stress.testing.plugin.nosql.redis.util.ReflectUtills;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class JedisInterceptor extends AbstractInterceptor {
    private final static Map<String, List<Method>> methodMap;
    private JedisMethodArgsResolver jedisMethodArgsResolver;

    static {
        methodMap = ReflectUtills.resolveMethodMap(JedisMethodArgsResolver.class);
    }

    @Override
    public void init(AgentConfig agentConfig, PluginConfig pluginConfig) {
        super.init(agentConfig, pluginConfig);
        jedisMethodArgsResolver = new JedisMethodArgsResolver(agentConfig, pluginConfig);
    }

    @Override
    public InvokeResult invoke(Method method, Object[] args, Object zuper, Object thiz) {
        if (!StressTesting.enable(getAgentConfig(), getPluginConfig(), TraceContextHolder.getTraceContext())) {
            return InvokeResult.invoked();
        }

        if (args == null || args.length == 0) {
            return InvokeResult.invoked();
        }

        Method argsResolveMethod = ReflectUtills.getArgsResolveMethod(method, methodMap);

        if (argsResolveMethod != null) {
            try {
                ResolveResult resolveResult = (ResolveResult) argsResolveMethod.invoke(jedisMethodArgsResolver, args);
                if (resolveResult.isKeyRenamedBefore()) {
                    return InvokeResult.invoked();
                } else {
                    args = resolveResult.getArgs();
                }
            } catch (Exception e) {
                // warning log
                return InvokeResult.invoked();
            }
        }

        try {
            Object invoke = method.invoke(thiz, args);
            return InvokeResult.invoked(invoke);
        } catch (Exception e) {
            return InvokeResult.invoked();
        }
    }
}
